---
author: Marcus Rohrmoser
categories:
- en
- development
date: "2010-08-26T16:05:18+00:00"
tags:
- CGFont
- Cocoa
- iOS
- iPhone
- Objective C
- OTF
- TrueType
- TTF
- UIFont
- UILabel
title: UILabel with a (custom) CGFont
type: post
url: /2010/08/uilabel-with-a-custom-cgfont/
yourls_shorturl:
- http://s.mro.name/3j
---
[UILabel's font property][1] accepts [UIFont][2]s – but strange enough there's no way to get a custom loaded [CGFont][3] (from a [ttf][4] or [otf][5] file) converted into such an UIFont. You're stuck with the iPhone's pre-installed fonts – at least when you have to support iOS 3.0 devices.

After googling a bit and searching [Stackoverflow][6] I found the solutions presented there not ideal or [great, but too heavy weight][7].

So I inherited UILabel with a very lean custom class UILabelWithCGFont and overloaded it's [drawTextInRect:][8] method like this:

<pre class="line-numbers"><code class="language-objc">
-(void)drawTextInRect:(CGRect)rect
{
  MRLogD(@"(%f,%f) (%f,%f)", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
  if ( _CGFont == NULL ) {
    [super drawTextInRect:rect];
    return;
  }
  NSAssert(_mapping != NULL, @"Mapping function pointer not set.");

  // prepare the target graphics context.
  const CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGContextSaveGState(ctx);
  {
    // prepare the glyphs array to draw
    const NSString *txt = self.text;
    const size_t glyphCount = txt.length;
    CGGlyph glyphs[glyphCount];
    {
      // turn the string txt into glyphs (indices into the font):
      // give non-allocating unicode character retrieval a try:
      const UniChar *raw_unichars = CFStringGetCharactersPtr( (CFStringRef)txt );
      const UniChar *unichars = raw_unichars == NULL ? malloc( glyphCount * sizeof(UniChar) ) : raw_unichars;
      NSAssert(unichars != NULL, @"unichars not allocated");
      if ( raw_unichars == NULL )
        CFStringGetCharacters( (CFStringRef)txt, CFRangeMake(0, txt.length), (UniChar *)unichars );
      for ( int i = glyphCount - 1; i &gt;= 0; i-- )
        glyphs[i] = _mapping(unichars[i]);
      if ( raw_unichars == NULL )
        free( (void *)unichars );
    }

    CGContextSetFont(ctx, _CGFont);
    CGContextSetFontSize(ctx, self.font.pointSize);
    CGContextSetTextMatrix( ctx, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0) );

    // first print 'invisible' to measure size:
    CGContextSetTextDrawingMode(ctx, kCGTextInvisible);
    const CGPoint pre = CGContextGetTextPosition(ctx);
    CGContextShowGlyphs(ctx, glyphs, glyphCount);
    const CGPoint post = CGContextGetTextPosition(ctx);
    // restore text position
    CGContextSetTextPosition(ctx, pre.x, pre.y);

    // centered horizontal + vertical:
    NSAssert( (int)rect.origin.x == 0, @"origin.x not zero" );
    NSAssert( (int)rect.origin.y == 0, @"origin.y not zero" );
    NSAssert(self.baselineAdjustment == UIBaselineAdjustmentAlignCenters, @"vertical alignment not 'center'");
    NSAssert(self.textAlignment == UITextAlignmentCenter, @"horizontal alignment not 'center'");
    const CGPoint p = CGPointMake( ( rect.size.width - (post.x - pre.x) ) / 2, (rect.size.height + self.font.pointSize + pre.y) / 2 );

    // finally render it to the graphics context:
    CGContextSetTextDrawingMode(ctx, kCGTextFill);
    CGContextSetFillColorWithColor(ctx, self.textColor.CGColor);
    CGContextShowGlyphsAtPoint(ctx, p.x, p.y, glyphs, glyphCount);
  }
  CGContextRestoreGState(ctx);
}
</code></pre>

**Usage:** Just turn the UILabel instances in Interface Builder into UILabelWithCGFont and implement the [UIViewController::viewDidLoad][9] method like this:

<pre class="line-numbers"><code class="language-objc">
CGGlyph unicode2glyphDeutscheDruckschrift(UniChar c)
{
  if ( '0' &lt; = c &#038;&#038; c &lt;= '9' )
    return c + (16 - '0');
  if ( 'A' &lt;= c &#038;&#038; c &lt;= 'Z' )
    return c + (32 - 'A');
  if ( 'a' &lt;= c &#038;&#038; c &lt;= 'z' )
    return c + (58 - 'a');
  return 0;
}

-(void)viewDidLoad
{
  [super viewDidLoad];
  ...
  [fontLabel setFontFromFile:@"DeutscheDruckschrift" ofType:@"ttf" mapping:unicode2glyphDeutscheDruckschrift];
  ...
}
</code></pre>

See this [github gist][10] for the complete implementation.

The mapping from [Unicode][11] character codes to [glyph][12] indices (inside the [font description][4]) currently is done via a C mapping function you have to provide a [function pointer][13] for. A later implementation could map the unicode character code to the glyph name and leverage  [CGFontGetGlyphWithGlyphName][14] and render the custom mapping function obsolete.

<!--more-->

 [1]: http://developer.apple.com/iphone/library/documentation/uikit/reference/UILabel_Class/Reference/UILabel.html#//apple_ref/doc/uid/TP40006797-CH3-SW5
 [2]: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIFont_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UIFont
 [3]: http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html
 [4]: http://en.wikipedia.org/wiki/TrueType
 [5]: http://en.wikipedia.org/wiki/OpenType
 [6]: http://stackoverflow.com/questions/360751/can-i-embed-a-custom-font-in-an-iphone-application
 [7]: http://github.com/zynga/FontLabel
 [8]: http://developer.apple.com/iphone/library/documentation/uikit/reference/UILabel_Class/Reference/UILabel.html#//apple_ref/doc/uid/TP40006797-CH3-SW10
 [9]: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW25
 [10]: http://gist.github.com/551646
 [11]: http://unicode.org/
 [12]: http://en.wikipedia.org/wiki/Glyph
 [13]: http://en.wikipedia.org/wiki/Function_pointer
 [14]: http://developer.apple.com/iphone/library/documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html#//apple_ref/doc/uid/TP30000953-CH1g-SW13